﻿using System;
using System.Collections.Generic;
using System.Reflection;
using MugenInjection.Interception.Interface;

namespace MugenInjection.Interception
{
    /// <summary>
    /// Represents the interceptor that map interceptors to actions.
    /// </summary>
    public class ActionInterceptorProcess : ISimpleInterceptorProcess
    {
        #region Nested type: InterceptionMember

        public struct InterceptionMember : IEquatable<InterceptionMember>
        {
            #region Equality members

            /// <summary>
            /// Indicates whether the current object is equal to another object of the same type.
            /// </summary>
            /// <returns>
            /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
            /// </returns>
            /// <param name="other">An object to compare with this object.</param>
            public bool Equals(InterceptionMember other)
            {
                return IinterceptorType.Equals(other.IinterceptorType) && Equals(MemberInfo, other.MemberInfo);
            }

            /// <summary>
            /// Indicates whether this instance and a specified object are equal.
            /// </summary>
            /// <returns>
            /// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
            /// </returns>
            /// <param name="obj">Another object to compare to. </param><filterpriority>2</filterpriority>
            public override bool Equals(object obj)
            {
                if (ReferenceEquals(null, obj)) return false;
                return obj is InterceptionMember && Equals((InterceptionMember) obj);
            }

            /// <summary>
            /// Returns the hash code for this instance.
            /// </summary>
            /// <returns>
            /// A 32-bit signed integer that is the hash code for this instance.
            /// </returns>
            /// <filterpriority>2</filterpriority>
            public override int GetHashCode()
            {
                unchecked
                {
                    return (IinterceptorType.GetHashCode()*397) ^ (MemberInfo != null ? MemberInfo.GetHashCode() : 0);
                }
            }

            public static bool operator ==(InterceptionMember left, InterceptionMember right)
            {
                return left.Equals(right);
            }

            public static bool operator !=(InterceptionMember left, InterceptionMember right)
            {
                return !left.Equals(right);
            }

            #endregion

            #region Fields

            public InterceptorType IinterceptorType;

            public MemberInfo MemberInfo;

            #endregion

            #region Constructors

            /// <summary>
            /// Initializes a new instance of the <see cref="InterceptionMember"/> class.
            /// </summary>
            public InterceptionMember(InterceptorType iinterceptorType, MemberInfo memberInfo)
            {
                IinterceptorType = iinterceptorType;
                MemberInfo = memberInfo;
            }

            #endregion
        }

        #endregion

        #region Fields

        public Dictionary<InterceptionMember, Action<IInterceptor>> Interceptors { get; private set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="ActionInterceptorProcess"/> class.
        /// </summary>
        public ActionInterceptorProcess()
        {
            Interceptors = new Dictionary<InterceptionMember, Action<IInterceptor>>();
        }

        #endregion

        #region Implementation of ISimpleInterceptorProcess

        /// <summary>
        /// Gets the priority.
        /// </summary>
        public int Priority
        {
            get { return 0; }
        }

        /// <summary>
        /// Intercepts all actions.
        /// </summary>
        /// <param name="interceptor">The specified <see cref="IInterceptor"/>.</param>
        public void Intercept(IInterceptor interceptor)
        {
            Action<IInterceptor> invoke;
            if (Interceptors.TryGetValue(new InterceptionMember(interceptor.InterceptorType, interceptor.Proxy.Member), out invoke))
            {
                invoke(interceptor);
                return;
            }
            interceptor.ProcessOriginal();
        }

        #endregion
    }
}